#include "parser.hpp"

void config_ns::ParseConfig( Config & config,  Scene & scene)
{
    std::string s("config.json");
    ParseConfig( config, scene, s);
}

void config_ns::ParseConfig ( Config & config, Scene & scene, std::string file_name)
{
    ptree _pt;
    boost::property_tree::json_parser::read_json( file_name,_pt);

    config.nThread   = _pt.get< uint>  ("nThreads");
    config.shadow    = _pt.get< bool>  ("shadow");
    config.precision = _pt.get< real_t>("precision");
    config.max_deep  = _pt.get< uint>  ("max_deep");
    
    config.scene_size = _pt.get< real_t>("scene.size");

    config.output_file = _pt.get< std::string>("output_file");
    std::string format = _pt.get < std::string>("output_format");

    if ( format == "jpg" || format == "JPG")
    {
        config.output_format = IL_JPG;
        config.output_file += ".jpg";
    }else
    if ( format == "PNG" || format == "png")
    {
        config.output_format = IL_PNG;
        config.output_file += ".png";
    }else
    {
        config.output_format = IL_BMP;
        config.output_file += ".bmp";
    }

    ParseCamera( config,  _pt);
    ParseScene ( config,  scene,  _pt);
}

void config_ns::ParseCamera( Config & config, ptree & _pt)
{
    config.camera_position.x( _pt.get<real_t>("camera.position.x"));
    config.camera_position.y( _pt.get<real_t>("camera.position.y"));
    config.camera_position.z( _pt.get<real_t>("camera.position.z"));
    
    config.camera_direction.x( _pt.get<real_t>("camera.direction.x"));
    config.camera_direction.y( _pt.get<real_t>("camera.direction.y"));
    config.camera_direction.z( _pt.get<real_t>("camera.direction.z"));
    
    config.camera_normal.x( _pt.get<real_t>("camera.normal.x"));
    config.camera_normal.y( _pt.get<real_t>("camera.normal.y"));
    config.camera_normal.z( _pt.get<real_t>("camera.normal.z"));
    
    config.width_px = _pt.get<int> ("camera.width_px");
    config.height_px = _pt.get<int>("camera.height_px");
    
    config.width  = _pt.get<real_t>("camera.width");
    config.height = config.width * (real_t)config.height_px / (real_t)config.width_px;
    config.angle  = _pt.get<real_t>("camera.angle");
}

void config_ns::ParseScene( Config & config, Scene & scene, ptree & _pt)
{
    ptree tree_lights =  _pt.get_child("scene.lights");

    ptree::const_iterator end = tree_lights.end();
    
    real_t sum_r, sum_g, sum_b;
    sum_r = config.background_color.r;
    sum_g = config.background_color.g;
    sum_b = config.background_color.b;
    for ( ptree::iterator it = tree_lights.begin(); it != end; it++)
    {
        Light light;

        light.color.r = it->second.get< real_t>("color.r");
        light.color.g = it->second.get< real_t>("color.g");
        light.color.b = it->second.get< real_t>("color.b");
        
        sum_r += light.color.r;
        sum_g += light.color.g;
        sum_b += light.color.b;
        
        light.position.x( it->second.get< real_t>("position.x"));
        light.position.y( it->second.get< real_t>("position.y"));
        light.position.z( it->second.get< real_t>("position.z"));

        scene.light.push_back( light);
    }
    real_t max_c;
    if ( sum_r > sum_g)
    {
        if ( sum_r > sum_b)
        {
            max_c = sum_r;
        }
        else
        {
            max_c = sum_b;
        }
    }
    else
    {
        if ( sum_g > sum_b)
        {
            max_c = sum_g;
        }
        else
        {
            max_c = sum_b;
        }
    }
    
    
    if ( max_c > 1.0)
    {
        max_c = 1.0 / max_c;
        for ( uint i = 0; i < scene.light.size(); i++)
        {
            scene.light[ i].color.r *= max_c;
            scene.light[ i].color.g *= max_c;
            scene.light[ i].color.b *= max_c;
        }
    }

    ptree tree_primitives = _pt.get_child("scene.primitives");

    end = tree_primitives.end();
    for ( ptree::iterator it = tree_primitives.begin(); it != end; it++)
    {
        std::string type =  it->second.get< std::string>( "type");
        if ( type == "sphere")
        {
            scene.addSphere( it->second);
        }else
        if ( type == "tor")
        {
            scene.addTor( it->second);
        }else
        if ( type == "cube")
        {
            scene.addCube( it->second);
        }else
        if ( type == "triangle")
        {
            scene.addTriangle( it->second);
        }else
        {
            std::cout << "Unknown primitive type:" << type << std::endl;
        }

    }

}
